/**
 * BrandBigData.com Inc.
 * Copyright (c) 2016 All Rights Reserved.
 */
package com.qibao.toolkit.util;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * @author xumin
 * @version $Id:CompressUtils.java, v0.1 2017/7/30 13:35 xumin
 */
public abstract class CompressUtils {
    private static final Logger logger = LoggerFactory.getLogger(CompressUtils.class);

    private static final ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)          // 允许转义字符
            .configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true).configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);                                            // 允许单引号

    /**
     * 以json+gzip压缩的方式存储数据
     *
     * @param str
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T decode(String str, Class<T> clazz) {
        if (StringUtils.isEmpty(str)) {
            return null;
        }
        byte[] decompress = decompress(str);
        try {
            return objectMapper.readValue(decompress, clazz);
        } catch (IOException e) {
            logger.error("反序列化gzip数据异常: data:{}", new String(decompress));
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public static <T> T decode(String str, TypeReference<T> typeReference) {
        if (StringUtils.isEmpty(str)) {
            return null;
        }
        byte[] decompress = decompress(str);
        try {
            return objectMapper.readValue(decompress, typeReference);
        } catch (IOException e) {
            logger.error("反序列化gzip数据异常: data:{}", new String(decompress));
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public static String encode(Object object) {
        try {
            if (object instanceof String) {
                return compress((String) object);
            }
            return compress(objectMapper.writeValueAsBytes(object));
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public static String compress(String str) {
        if (StringUtils.isBlank(str)) {
            return str;
        }
        return compress(str.getBytes());
    }

    public static String compress(byte[] bytes) {
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            GzipCompressorOutputStream outputStream = new GzipCompressorOutputStream(byteArrayOutputStream);
            outputStream.write(bytes);
            outputStream.close();
            return Base64.encodeBase64String(byteArrayOutputStream.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public static byte[] decompress(String str) {
        try {
            GzipCompressorInputStream inputStream = new GzipCompressorInputStream(new ByteArrayInputStream(Base64.decodeBase64(str)));
            return IOUtils.toByteArray(inputStream);
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public static String decompressToString(String str) {
        if (StringUtils.isBlank(str)) {
            return str;
        }
        try {
            GzipCompressorInputStream inputStream = new GzipCompressorInputStream(new ByteArrayInputStream(Base64.decodeBase64(str)));
            return new String(IOUtils.toByteArray(inputStream));
        } catch (IOException e) {
            logger.error("解压gzip数据异常: data:{}", str);
            throw new RuntimeException(e.getMessage(), e);
        }
    }

}
